import socket
import threading
from typing import Optional, List, Tuple
from .port_abstract import PortAbstract


class TCPServerAbstract(PortAbstract):
    """
    TCP 服务端抽象类
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.host: str = 'localhost'
        self.port: int = 8080
        self.server_socket: Optional[socket.socket] = None
        self.client_sockets: List[socket.socket] = []
        self.client_lock = threading.Lock()
        self.max_clients = 10

    @PortAbstract.openwapper
    def open(self, host=None, port=None, max_clients=10, **kwargs):
        """
        打开 TCP 服务器
        """
        if host is None:
            host = self.host
        if port is None:
            port = self.port

        self.host = host
        self.port = port
        self.max_clients = max_clients

        # 创建服务器socket
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen(self.max_clients)

        # 启动接受客户端连接的线程
        self.threads['accept'] = threading.Thread(target=self._accept_clients, daemon=True)
        self.threads['accept'].start()

    @PortAbstract.closewapper
    def close(self):
        """
        关闭 TCP 服务器和所有客户端连接
        """
        # 关闭所有客户端连接
        with self.client_lock:
            for client_socket in self.client_sockets:
                try:
                    client_socket.close()
                except:
                    pass
            self.client_sockets.clear()

        # 关闭服务器socket
        if self.server_socket:
            self.server_socket.close()
            self.server_socket = None

    def _accept_clients(self):
        """
        接受客户端连接的内部方法
        """
        while not self.evt.is_set() and self.server_socket:
            try:
                client_socket, client_addr = self.server_socket.accept()
                print(f"新的客户端连接: {client_addr}")

                with self.client_lock:
                    self.client_sockets.append(client_socket)

                # 为每个客户端启动读取线程
                client_thread = threading.Thread(
                    target=self._handle_client,
                    args=(client_socket, client_addr),
                    daemon=True
                )
                client_thread.start()

            except socket.error as e:
                if not self.evt.is_set():
                    print(f"接受客户端连接时出错: {e}")
                break

    def _handle_client(self, client_socket: socket.socket, client_addr: Tuple[str, int]):
        """
        处理单个客户端连接
        """
        client_name = f"{client_addr[0]}:{client_addr[1]}"

        try:
            while not self.evt.is_set():
                try:
                    # 读取数据
                    data = client_socket.recv(4096)
                    if not data:
                        break

                    # 处理数据
                    message = data.decode('utf-8')
                    print(f"收到来自 {client_name} 的消息: {message}")

                    # 将数据放入队列供其他模块处理
                    self.data_queue.put({
                        'client': client_name,
                        'data': message,
                        'timestamp': threading.get_ident()
                    })

                except socket.error as e:
                    print(f"从客户端 {client_name} 读取数据时出错: {e}")
                    break

        except Exception as e:
            print(f"处理客户端 {client_name} 时出错: {e}")

        finally:
            # 清理客户端连接
            with self.client_lock:
                if client_socket in self.client_sockets:
                    self.client_sockets.remove(client_socket)

            try:
                client_socket.close()
            except:
                pass

            print(f"客户端 {client_name} 已断开连接")

    def read(self):
        """
        从数据队列读取数据
        """
        try:
            if not self.data_queue.empty():
                return self.data_queue.get_nowait()
        except:
            pass
        return None

    def write(self, data, client_filter=None):
        """
        向客户端发送数据

        Args:
            data: 要发送的数据
            client_filter: 客户端过滤器，可以是客户端地址或回调函数
        """
        if not self.Writeable:
            return

        data_str = str(data)
        if not isinstance(data_str, str):
            data_str = str(data_str)

        data_bytes = data_str.encode('utf-8')

        with self.client_lock:
            clients_to_remove = []

            for client_socket in self.client_sockets:
                try:
                    # 检查客户端过滤器
                    if client_filter:
                        client_addr = client_socket.getpeername()
                        client_name = f"{client_addr[0]}:{client_addr[1]}"

                        if callable(client_filter):
                            if not client_filter(client_name):
                                continue
                        elif client_name != client_filter:
                            continue

                    # 发送数据
                    client_socket.send(data_bytes)
                    print(f"向客户端发送数据: {data_str}")

                except socket.error:
                    # 标记需要移除的客户端
                    clients_to_remove.append(client_socket)

            # 移除断开连接的客户端
            for client_socket in clients_to_remove:
                self.client_sockets.remove(client_socket)

    def broadcast(self, data):
        """
        向所有客户端广播数据
        """
        self.write(data)

    def heart(self) -> bool:
        """
        检查服务器状态
        """
        return self.server_socket is not None and not self.evt.is_set()

    def get_port_list(self) -> list:
        """
        获取客户端连接列表
        """
        client_list = []
        with self.client_lock:
            for client_socket in self.client_sockets:
                try:
                    client_addr = client_socket.getpeername()
                    client_list.append(f"{client_addr[0]}:{client_addr[1]}")
                except:
                    pass
        return client_list

    def get_port_params(self) -> dict:
        """
        获取服务器配置参数
        """
        return {
            "host": {
                "value": self.host,
                "type": str,
                "required": True,
                "desc": "服务器主机地址"
            },
            "port": {
                "value": self.port,
                "type": int,
                "required": True,
                "desc": "服务器端口号"
            },
            "max_clients": {
                "value": self.max_clients,
                "type": int,
                "required": False,
                "desc": "最大客户端连接数"
            }
        }

    def get_client_count(self) -> int:
        """
        获取当前客户端连接数量
        """
        with self.client_lock:
            return len(self.client_sockets)


class TCPClientAbstract(PortAbstract):
    """
    TCP 客户端抽象类
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.server_host: str = 'localhost'
        self.server_port: int = 8080
        self.client_socket: Optional[socket.socket] = None
        self.reconnect_attempts = 3
        self.reconnect_delay = 2

    @PortAbstract.openwapper
    def open(self, host=None, port=None, **kwargs):
        """
        连接到 TCP 服务器
        """
        if host is None:
            host = self.server_host
        if port is None:
            port = self.server_port

        self.server_host = host
        self.server_port = port

        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect((self.server_host, self.server_port))
        print(f"已连接到服务器 {self.server_host}:{self.server_port}")

    @PortAbstract.closewapper
    def close(self):
        """
        关闭客户端连接
        """
        if self.client_socket:
            self.client_socket.close()
            self.client_socket = None

    def read(self):
        """
        从服务器读取数据
        """
        try:
            if self.client_socket:
                # 设置非阻塞模式，避免read线程阻塞
                self.client_socket.settimeout(0.1)
                try:
                    data = self.client_socket.recv(4096)
                    if data:
                        message = data.decode('utf-8')
                        print(f"收到服务器数据: {message}")
                        return message
                except socket.timeout:
                    pass
        except Exception as e:
            print(f"读取数据时出错: {e}")
            if self.AutoReconnect:
                raise
        return None

    def write(self, data):
        """
        向服务器发送数据
        """
        if not self.Writeable or not self.client_socket:
            return

        data_str = str(data)
        if not isinstance(data_str, str):
            data_str = str(data_str)

        try:
            self.client_socket.send(data_str.encode('utf-8'))
            print(f"向服务器发送数据: {data_str}")
        except socket.error as e:
            print(f"发送数据时出错: {e}")
            # 将数据重新放回队列，等待重连后发送
            if self.AutoReconnect:
                self.writer_queue.put(data)
            raise e

    def heart(self) -> bool:
        """
        检查连接状态
        """
        if not self.client_socket:
            return False

        try:
            # 发送心跳包或检查socket状态
            self.client_socket.send(b'')
            return True
        except socket.error:
            return False

    def get_port_list(self) -> list:
        """
        获取可用的服务器列表（简化实现）
        """
        # 在实际应用中，这里可以实现服务器发现逻辑
        return [f"{self.server_host}:{self.server_port}"]

    def get_port_params(self) -> dict:
        """
        获取客户端配置参数
        """
        return {
            "server_host": {
                "value": self.server_host,
                "type": str,
                "required": True,
                "desc": "服务器主机地址"
            },
            "server_port": {
                "value": self.server_port,
                "type": int,
                "required": True,
                "desc": "服务器端口号"
            }
        }


# 创建具体的 TCP 服务器和客户端类
TCPServer = TCPServerAbstract.get_instance(perms=7)  # 读写和自动重连权限
TCPClient = TCPClientAbstract.get_instance(perms=7)  # 读写和自动重连权限

